<!doctype html>
<title>Test promises from MediaDevices methods in a discarded browsing
  context</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body></body>
<script>
let devices;
let child_DOMException;
setup(() => {
  const frame = document.createElement('iframe');
  document.body.appendChild(frame);
  devices = frame.contentWindow.navigator.mediaDevices;
  child_DOMException = frame.contentWindow.DOMException;
  frame.remove();
});

// https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia
// If the current settings object's responsible document is NOT fully active,
// return a promise rejected with a DOMException object whose name attribute
// has the value "InvalidStateError".
promise_test(async () => {
  // `catch()` is used rather than static Promise methods because microtasks
  // for `PromiseResolve()` do not run when Promises in inactive Documents are
  // involved.  Whether microtasks for `catch()` run depends on the realm of
  // the handler rather than the realm of the Promise.
  // See https://github.com/whatwg/html/issues/5319.
  let promise_already_rejected = false;
  let rejected_reason;
  devices.getUserMedia({audio:true}).catch(reason => {
    promise_already_rejected = true;
    rejected_reason = reason;
  });
  // Race a settled promise to check that the returned promise is already
  // rejected.
  await Promise.reject().catch(() => {
    assert_true(promise_already_rejected,
                'should have returned an already-rejected promise.');
    assert_throws_dom('InvalidStateError', child_DOMException,
                      () => { throw rejected_reason });
  });
}, 'getUserMedia() in a discarded browsing context');

// https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices
// https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-for-spec-authors
// Promise resolution occurs only in parallel steps, so, if there is any
// manipulation of the Promise, it would occur through a queued task.
promise_test(() => {
  let promise_is_pending = true;
  // Don't use `finally()`, because it uses `PromiseResolve()` and so
  // microtasks don't run.
  devices.enumerateDevices().then(() => promise_is_pending = false,
                                  () => promise_is_pending = false);
  return Promise.resolve().then(() => {
    assert_true(promise_is_pending,
                'should have returned a pending promise.');
  });
}, 'enumerateDevices() in a discarded browsing context');
</script>
